package com.aya.copy.tools.action;

import com.aya.copy.tools.action.generate.Generator;
import com.aya.copy.tools.action.generate.ListGenerator;
import com.aya.copy.tools.action.generate.NoneGenerator;
import com.aya.copy.tools.action.setter.DefaultTypeHandlerFactory;
import com.aya.copy.tools.action.setter.TypeHandler;
import com.aya.copy.tools.action.setter.TypeHandlerFactory;
import com.intellij.database.datagrid.DataConsumer;
import com.intellij.lang.jvm.types.DefaultJvmTypeVisitor;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiParameter;
import com.intellij.psi.PsiType;
import com.intellij.psi.impl.source.PsiClassReferenceType;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class GridProcessor {
    private TypeHandlerFactory typeHandlerFactory = new DefaultTypeHandlerFactory();


    public String process(PsiClass selectedClass, List<DataConsumer.Row> selectedRows, List<DataConsumer.Column> columns) {
        PsiMethod[] allFields = selectedClass.getAllMethods();
        Map<String, PsiMethod> fieldMap = methodsToMap(allFields);

        StringBuilder stringBuilder = new StringBuilder();
        boolean generateList = selectedRows.size() > 1;
        Generator listGenerator = new NoneGenerator();
        if (generateList) {
            listGenerator = new ListGenerator(selectedClass);
        }
        stringBuilder.append(listGenerator.getDeclaring());
        for (DataConsumer.Row selectedRow : selectedRows) {
            BeanDefinition beanDefinition = buildBean(selectedRow.rowNum, selectedClass);
            stringBuilder.append(beanDefinition.buildDeclaring()).append("\n");
            for (DataConsumer.Column column : columns) {
                Object value = column.getValue(selectedRow);
                String appendContent = buildAppendContent(fieldMap,
                        beanDefinition.getName(),
                        column.getName(),
                        value);
                if (appendContent != null) {
                    stringBuilder.append(appendContent).append("\n");
                }
            }
            stringBuilder.append(listGenerator.addBean(beanDefinition.getName()));
            stringBuilder.append("\n");
        }
        return stringBuilder.toString();
    }


    private BeanDefinition buildBean(int rowNum, PsiClass selectedClass) {
        BeanDefinition beanDefinition = new BeanDefinition();
        beanDefinition.setPsiClass(selectedClass);
        String name = selectedClass.getName();
        String beanName = name.substring(0, 1).toLowerCase() + name.substring(1);
        beanDefinition.setName(beanName + rowNum);
        return beanDefinition;
    }

    private String buildAppendContent(Map<String, PsiMethod> fieldMap,
                                      String beanName,
                                      String name,
                                      Object value) {
        PsiMethod psiMethod = matchField(fieldMap, name);
        if (psiMethod == null) {
            return null;
        }
        PsiParameter psiParameter = psiMethod.getParameterList().getParameter(0);
        TypeHandler typeHandler = determineTypeHandler(psiParameter.getType());
        if (typeHandler == null) {
            return null;
        }
        String strValue = typeHandler.setValue(value);
        StringBuilder stringBuilder = new StringBuilder();
        String setMethodName = psiMethod.getName();
        stringBuilder.append(beanName).append(".").append(setMethodName).append("(").append(strValue).append(");");
        return stringBuilder.toString();
    }


    private Map<String, PsiMethod> methodsToMap(PsiMethod[] allFields) {
        Map<String, PsiMethod> map = new HashMap<>();

        for (PsiMethod psiField : allFields) {

            if (psiField.hasParameters() &&
                    psiField.getName().startsWith("set")) {
                String key = psiField.getName().toUpperCase();
                int offset = "set".length();
                // 取消set前缀

                key = key.substring(offset);
                map.put(key, psiField);
            }
        }
        return map;
    }


    private TypeHandler determineTypeHandler(PsiType psiType) {
        TypeHandler setterFactory = psiType.accept((DefaultJvmTypeVisitor<TypeHandler>) typeParam -> {
            String qualifiedName = ((PsiClassReferenceType) typeParam).getReference().getQualifiedName();
            return typeHandlerFactory.getTypeHandler(qualifiedName);
        });
        return setterFactory;
    }

    private PsiMethod matchField(Map<String, PsiMethod> fieldMap, String fieldName) {
        String key = fieldName.toUpperCase();
        // 取消下划线
        key = key.replace("_", "");
        return fieldMap.get(key);
    }

}
